Expand description
Overview
A library crate providing a dependency-free, pure rust implementation of the cashaddr codec.
Features
- Trait-based interfaces for transcoding arbitrary sequence of bytes to/from cashaddr strings
- Generalized interface supporting all standard and many non-standard use-cases
- Convenience methods for succinct expression of common conversion parameters
- Custom hash types
- Arbitrary prefixes
- Elided prefix
- Descriptive error types
- Payload struct for encapsulating parsed cashaddr payload and hash type
About the Codec
Cashaddr is a base32-based encoding scheme designed to encode a hash digest and hash type which describes the use case for the hash. The hash is an arbitrary sequence of either 20, 24, 28, 32, 40, 48, 56, or 64 bytes. The cashaddr format represents this information as a string which consists of 2 parts: an arbitrary user-defined prefix, and a base32-encoded representation of the hash, hash type, hash length, and a checksum which checks both the hash payload and the user prefix. For details, see the cashaddr spec
Attribution
Most of the codec algorithm logic was copied from
bitcoincash-addr
.
This crate seeks to improve on bitcoincash-addr
by providing a more
generalized and ergonomic user interface, adding support for arbitrary
prefixes, and reducing scope to only matters directly related the cashaddr
codec itself (base58check codec removed from scope).
Usage
Encoding
Encoding a sequence of bytes into a cashaddr string is acheived via the CashEnc
trait. This
trait’s methods are used to encode the bytes sequence, and is implemented for all types which
implement [AsRef<[u8]>
]
use cashaddr::CashEnc;
let payload = b"\xf5\xbfH\xb3\x97\xda\xe7\x0b\xe8+<\xcaG\x93\xf8\xeb+l\xda\xc9";
// encode the payload bytes as a p2sh cashaddr, using "bchtest" as the prefix
let cashaddr = "bchtest:pr6m7j9njldwwzlg9v7v53unlr4jkmx6eyvwc0uz5t";
assert_eq!(payload.encode_p2sh("bchtest").unwrap(), cashaddr);
// encode the payload bytes as a p2pkh cashaddr, using "bitcoincash" as the prefix
let cashaddr = "bitcoincash:qr6m7j9njldwwzlg9v7v53unlr4jkmx6eylep8ekg2";
assert_eq!(payload.encode_p2pkh("bitcoincash").unwrap(), cashaddr);
// arbitrary prefixes are supported
let cashaddr = "foobar:qr6m7j9njldwwzlg9v7v53unlr4jkmx6eyde268tla";
assert_eq!(payload.encode_p2pkh("foobar").unwrap(), cashaddr);
Incorrect payload length is detected and captured during encoding
use cashaddr::{CashEnc, EncodeError};
let payload = b"\xf5\xbfH\xb3\x97\xda\xe7\x0b\xe8+<\xcaG\x93\xf8\xeb+l\xda\xc9t";
match payload.encode_p2pkh("someprefix") {
Err(EncodeError::IncorrectPayloadLen(21)) => (), // pass
Err(EncodeError::IncorrectPayloadLen(_)) => panic!(
"Detected incorrect payload length, but failed to capture the correct actual input len"
),
Err(e) => panic!("Detected unexpected error {}", e),
Ok(_) => panic!("Failed to detect incorrect payload length"),
}
Decoding
Decoding a cashaddr str
to a binary payload is acheived via the Payload
type which
encapsulates the payload itself and the detected hash type. Parsing is provided by the
FromStr
trait
use cashaddr::{Payload, HashType, DecodeError};
let EXPECTED_PAYLOAD = b"\xf5\xbfH\xb3\x97\xda\xe7\x0b\xe8+<\xcaG\x93\xf8\xeb+l\xda\xc9";
// Use parse() to decode a P2PKH cashaddr string to a `Payload`
let cashaddr = "bitcoincash:qr6m7j9njldwwzlg9v7v53unlr4jkmx6eylep8ekg2";
let payload: Payload = cashaddr.parse().unwrap();
assert_eq!(payload.as_ref(), EXPECTED_PAYLOAD);
assert_eq!(payload.hash_type(), HashType::P2PKH);
// Use parse() to decode a P2SH cashaddr string to a `Payload`
let cashaddr = "bitcoincash:pr6m7j9njldwwzlg9v7v53unlr4jkmx6eyguug74nh";
let payload: Payload = cashaddr.parse().unwrap();
assert_eq!(payload.as_ref(), EXPECTED_PAYLOAD);
assert_eq!(payload.hash_type(), HashType::P2SH);
// arbitrary prefix are supported in decoding
let cashaddr = "foobar:qr6m7j9njldwwzlg9v7v53unlr4jkmx6eyde268tla";
let payload: Payload = cashaddr.parse().unwrap();
assert_eq!(payload.as_ref(), EXPECTED_PAYLOAD);
assert_eq!(payload.hash_type(), HashType::P2PKH);
// Decoding is canse insensitive in the second part of the cashaddr
let cashaddr = "foobar:qr6M7j9NJLdwwzLG9v7v53UNlr4jkmX6eyDe268tla";
let payload: Payload = cashaddr.parse().unwrap();
assert_eq!(payload.as_ref(), EXPECTED_PAYLOAD);
assert_eq!(payload.hash_type(), HashType::P2PKH);
// Decoding checks that the checksum is valid
// This char was changed to "8" -------↓
let cashaddr = "foobar:qr6M7j9NJLdwwzLG8v7v53UNlr4jkmX6eyDe268tla";
match cashaddr.parse::<Payload>() {
Err(DecodeError::ChecksumFailed(_)) => (),
_ => panic!("Failed to detect corrupt cashaddr checksum"),
}
Structs
Enums
u8
into a
cashaddr StringConstants
Traits
u8
) as a cashaddr string. This trait is implemented for all types
implementing AsRef<[u8]>
where the reference value is a slice of u8
representing the hash
payload bytes.